package fm.yichenet.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.binarywang.wxpay.bean.WxPayOrderNotifyResponse;
import com.github.binarywang.wxpay.bean.request.WxPayBaseRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayBaseResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.result.WxPayOrderQueryResult;
import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.service.WxPayService;
import com.github.binarywang.wxpay.service.impl.WxPayServiceImpl;
import com.github.binarywang.wxpay.util.SignUtils;
import com.mongodb.BasicDBObject;
import com.mongodb.DBObject;
import fm.cache.ConfigCache;
import fm.config.MainConfig;
import fm.dao.HibernateBaseDao;
import fm.dto.SystemUser;
import fm.entity.*;
import fm.entityEnum.*;
import fm.exception.BizException;
import fm.mongoService.UserService;
import fm.service.impl.ArticleAdServiceImpl;
import fm.util.CommonUtils;
import fm.util.DateUtils;
import fm.web.CurrentRequest;
import fm.yichenet.mongo.service.ArticleService;
import fm.yichenet.mongo.service.GoodMgrService;
import fm.yichenet.mongo.service.SmsService;
import fm.yichenet.service.OrderService;
import fm.yichenet.service.SectionService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.io.IOUtils;
import org.apache.solr.common.StringUtils;
import org.omg.CORBA.Current;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by 宏炜 on 2017-06-19.
 */
@Service
public class OrderServiceImpl implements OrderService {
    private static final Logger LOGGER = LoggerFactory.getLogger(OrderService.class);

    @Autowired
    HibernateBaseDao hibernateBaseDao;
    @Autowired
    SmsService smsService;
    @Autowired
    UserService userService;

    @Autowired
    ArticleAdServiceImpl articleAdService;
    @Autowired
    GoodMgrService goodMgrService;
    @Autowired
    MainConfig mainConfig;
    @Autowired
    ArticleService articleService;
    @Autowired
    SectionService sectionService;

    @Override
    public Map<String, Object> addOrder(List<OrderGood> paramsList, SystemUser wxUser) throws Exception {

        Timestamp now = new Timestamp(System.currentTimeMillis());


        for (OrderGood orderGood : paramsList) {
            if (CommonUtils.isEmpty(orderGood.getGoodId())) {
                throw new BizException("商品id不能为空");
            }
            if (CommonUtils.isEmpty(orderGood.getType())) {
                throw new BizException("订单类型不能为空");
            }
            if (CommonUtils.isEmpty(orderGood.getGoodNum())) {
                throw new BizException("商品数量不能为空");
            }
            if (CommonUtils.isEmpty(orderGood.getUnitPrice())) {
                throw new BizException("商品单价不能为空");
            }

            orderGood.setId(UUID.randomUUID().toString().replaceAll("-", ""));
            orderGood.setCreateTime(now);
            orderGood.setUserId((String) wxUser.getId());

            if (orderGood.getType().equals(OrderTypeEnum.EDIT_ORDER)) {
                orderGood.setStatus(OrderEnum.WAIT_EDIT_PRICE);
                orderGood.setUnitPrice(Double.valueOf(0));
                orderGood.setSumPrice(Double.valueOf(0));
            } else {

                orderGood.setStatus(OrderEnum.UNPAID);
                orderGood.setSumPrice((orderGood.getUnitPrice() * orderGood.getGoodNum()) + orderGood.getExpressPrice());
            }
            SystemUser shopUser = userService.getById(orderGood.getShopId());
            if (shopUser != null && StringUtils.isEmpty(shopUser.getPhone()) == false) {
                try {
                    smsService.businessSmsSend(shopUser.getPhone(), ActionTypeEnum.TRADE_ORDER.toString());
                } catch (Exception ex) {
                    LOGGER.error("短信发生失败!", ex);
                }
            }

            orderGood.setVersion(1L);
            if (orderGood.getUnitPrice().equals(new Double(0))) {
                orderGood.setStatus(OrderEnum.WAIT_EDIT_PRICE);
            }
            hibernateBaseDao.save(orderGood);

        }
//        orderTransaction.setAmount(amount);
//        hibernateBaseDao.save(orderTransaction);
        Map<String, Object> res = new HashedMap();
        res.put("orderList", paramsList);
        return res;
    }

    @Override
    public OrderArticleAd addArticleAdOrder(String articleId, BigDecimal totalFee, ArticleAdEnum adType, String startTime, String endTime) throws Exception {

        OrderArticleAd order = new OrderArticleAd();
        order.setStatus(OrderEnum.PAYING);
        order.setAdType(adType);
        order.setStartTime(new Timestamp(DateUtils.parseDate(startTime).getTime()));
        order.setEndTime(new Timestamp(DateUtils.parseDate(endTime).getTime()));
        order.setArticleId(articleId);
        order.setTotal(totalFee);
        order.setUserId((String) CurrentRequest.getCurrentUserId());

        hibernateBaseDao.save(order);
        return order;
    }

    @Override
    public OrderGood cancelOrder(String orderId, SystemUser wxUser) throws Exception {
        String hql = "from OrderGood where userId = ? and id = ?";
        OrderGood orderGood = (OrderGood) hibernateBaseDao.getUnique(hql, wxUser.getId(), orderId);
        if (!(orderGood.getStatus().equals(OrderEnum.UNPAID) || orderGood.getStatus().equals(OrderEnum.PAYMENT_TIMEOUT) || orderGood.getStatus().equals(OrderEnum.PAYMENT_FAIL))) {
            throw new BizException("当前订单状态无法取消订单");
        }
        if (CommonUtils.isEmpty(orderGood)) {
            throw new BizException("订单信息不存在");
        }
        orderGood.setStatus(OrderEnum.ORDER_CANCEL);
        OrderTransaction orderTransaction = (OrderTransaction) hibernateBaseDao.getById(OrderTransaction.class, orderGood.getTransactionOrderId());
        Double cancelAmount = orderGood.getSumPrice();
        orderTransaction.setAmount(orderTransaction.getAmount() - cancelAmount);
        hibernateBaseDao.update(orderGood);
        hibernateBaseDao.update(orderTransaction);
        return orderGood;
    }

    @Override
    public List<OrderGood> orderList(Integer pageSize, Integer pageNum, SystemUser wxUser) throws Exception {
        String hql = "from OrderGood where userId = ?";
        List<OrderGood> orderGoods = (List<OrderGood>) hibernateBaseDao.pageQuery(hql, pageNum, pageSize, wxUser.getId());
        return orderGoods;
    }

    @Override
    public Object prePayOrder(String targetId, ClientTypeEnum clientType, ProductTypeEnum productType, HttpServletRequest request) throws Exception {
        Object result = null;

        SystemUser user = (SystemUser) CurrentRequest.getCurrentUser();
        OrderTransaction orderTransaction = addOrderTransaction(targetId, productType);


        WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();

        String body = ConfigCache.getConfig("ORDER_CENTER_TITLE", "订单中心");
        orderRequest.setBody(body);

        orderRequest.setOutTradeNo(orderTransaction.getId());
        orderRequest.setTotalFee(WxPayBaseRequest.yuanToFee(String.valueOf(orderTransaction.getAmount())));//元转成分
        orderRequest.setOpenid(user.getOpenid());
        orderRequest.setNotifyURL(mainConfig.getDomain() + "/order/notify/" + clientType.toString() + "/" + productType.toString());


        switch (clientType) {
            case wechat:
                orderRequest.setTradeType("JSAPI");
                break;
            case app:
                orderRequest.setTradeType("APP");
                break;
            case web:
                orderRequest.setTradeType("NATIVE");
                OrderArticleAd order = articleAdService.getById(Long.parseLong(targetId));
                if (CommonUtils.isEmpty(order)) {
                    throw new BizException("订单不存在！");
                }
                orderRequest.setProductId(order.getArticleId());
                break;
            default:
                throw new BizException("参数类型错误");
        }
        WxPayService wxPayService = setWxPayConfig(clientType, productType);


        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("PRoxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }

        LOGGER.info("user pay info real ip : {}", ip);

        if (ip.contains(",")) {
            ip = ip.split(",")[0];
        }
        orderRequest.setSpbillCreateIp(ip);

        Timestamp now = new Timestamp(System.currentTimeMillis());
        Timestamp expiredTime = new Timestamp(now.getTime() + (30 * 60 * 1000));
        DateFormat sdf1 = new SimpleDateFormat("yyyyMMddHHmmss");

        orderRequest.setTimeStart(sdf1.format(now));
        orderRequest.setTimeExpire(sdf1.format(expiredTime));

        orderRequest.setAppid(mainConfig.getAppid());
        orderRequest.setMchId(mainConfig.getPartenerId());

        LOGGER.info("微信支付请求信息:{}", JSON.toJSONString(orderRequest));
        Map data = wxPayService.getPayInfo(orderRequest);
        LOGGER.info("支付请求结果:{}",JSON.toJSONString(data));

        switch (clientType) {
            case wechat:
                result = data;
                break;
            case web:
            case app:
                result = data;
                break;
            default:
                throw new BizException("参数类型错误");
        }


        updateOrderTransactionStatus(orderTransaction.getId(), PayStatusEnum.PAYING, productType);


        return result;
    }

    @Override
    public String notifyOrder(ClientTypeEnum clientType, ProductTypeEnum productType,
                              HttpServletRequest request, HttpServletResponse response) throws Exception {
        WxPayService wxPayService = setWxPayConfig(clientType, productType);
        String xmlResult = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
        LOGGER.info("支付回调结果：{}", xmlResult);

        WxPayOrderNotifyResult result = wxPayService.getOrderNotifyResult(xmlResult);
        String orderId = result.getOutTradeNo();
        String tradeNo = result.getTransactionId();
        String totalFee = WxPayBaseResult.feeToYuan(result.getTotalFee());
        LOGGER.info("订单:{}支付金额:{}元", tradeNo, totalFee);
        //回调之后主动查询一次
        WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(null, orderId);

        if (wxPayOrderQueryResult.getTradeState().equals("SUCCESS")) {
            updateOrderTransactionStatus(orderId, PayStatusEnum.PAID, productType);
            LOGGER.info("user openid :{} ,pay succeed update OrderTransaction id {} ,wxOrderId: {}", result.getOpenid(), orderId, tradeNo);
            LOGGER.info("user openid :{} ,pay succeed update OrderGood by OrderTransaction id {} ,wxOrderId: {}", result.getOpenid(), orderId, tradeNo);
        } else if (wxPayOrderQueryResult.getTradeState().equals("CLOSED") || wxPayOrderQueryResult.getTradeState().equals("PAYERROR")) {
            updateOrderTransactionStatus(orderId, PayStatusEnum.PAY_FAILED, productType);
            LOGGER.info("user openid :{} ,pay failed update OrderTransaction id {} ,wxOrderId: {}", result.getOpenid(), orderId, tradeNo);
        }

        return WxPayOrderNotifyResponse.success("处理成功!");
    }

    @Override
    public OrderTransaction addOrderTransaction(String targetIds, ProductTypeEnum productType) throws Exception {

        if (StringUtils.isEmpty(targetIds)) {
            throw new BizException("参数缺失");
        }

        Timestamp now = new Timestamp(System.currentTimeMillis());
        OrderTransaction orderTransaction = new OrderTransaction();
        orderTransaction.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        orderTransaction.setPayStatus(PayStatusEnum.UNPAID);
        orderTransaction.setCreateTime(now);
        orderTransaction.setUpdateTime(now);

        List<String> ids = Arrays.asList(targetIds.split(","));

        Double amount = Double.valueOf(0);
        for (String orderId : ids) {

            switch (productType) {
                case GOOD:
                    //商品类型的订单数据,获取商品订单的价格并更新商品订单关联这里生成的微信交易订单以方便交易查询
                    OrderGood orderGood = (OrderGood) hibernateBaseDao.getById(OrderGood.class, orderId);
                    if (orderGood.getStatus().equals(OrderEnum.WAIT_EDIT_PRICE) && (orderGood.getSumPrice() == null || orderGood.getSumPrice() == new Double(0))) {
                        throw new BizException("店家尚未改价，请联系店家改价后再尝试支付");
                    }
                    if (CommonUtils.isEmpty(orderGood)) {
                        throw new BizException("订单不存在或者已经过期，请重新下单！");
                    }

                    orderGood.setTransactionOrderId(orderTransaction.getId());
                    amount += orderGood.getSumPrice();
                    hibernateBaseDao.update(orderGood);
                    break;
                case FORUM_AD:
                    //资讯推广类型的数据，获取资讯所在的版块、推广的标记以确定价格
                    OrderArticleAd orderArticleAd = articleAdService.getById(Long.parseLong(orderId));
                    if (orderArticleAd == null) {
                        throw new BizException("推广订单不存在，请重新下单!");
                    }

                    orderArticleAd.setTransactionOrderId(orderTransaction.getId());
                    amount += orderArticleAd.getTotal().doubleValue();

                    articleAdService.updateOrder(orderArticleAd);
                    break;
                default:
                    throw new BizException("参数错误");
            }


        }
        orderTransaction.setAmount(amount);
        orderTransaction.setVersion(1L);
        hibernateBaseDao.save(orderTransaction);
        return orderTransaction;
    }

    @Override
    public WxPayOrderQueryResult getOrderPayResult(String orderId, ProductTypeEnum productType, ClientTypeEnum clientType) throws Exception {
        WxPayService wxPayService = setWxPayConfig(clientType, productType);
        String transactionId = null;
        switch (productType) {
            case GOOD:
                OrderGood orderGood = getOrderById(orderId);

                if (CommonUtils.isEmpty(orderGood)) {
                    throw new BizException("订单不存在!");
                }
                if (!CurrentRequest.isAdmin() && !CurrentRequest.getCurrentUserId().equals(orderGood.getUserId())) {
                    throw new BizException("无权查看他人订单信息,已记录您的IP，请谨慎操作!");
                }
                transactionId = orderGood.getTransactionOrderId();
                break;

            case FORUM_AD:
                OrderArticleAd orderArticleAd = articleAdService.getById(Long.parseLong(orderId));
                if (CommonUtils.isEmpty(orderArticleAd)) {
                    throw new BizException("订单不存在!");
                }
                if (!CurrentRequest.isAdmin() && !CurrentRequest.getCurrentUserId().equals(orderArticleAd.getUserId())) {
                    throw new BizException("无权查看他人订单信息,已记录您的IP，请谨慎操作!");
                }
                transactionId = orderArticleAd.getTransactionOrderId();
                break;

        }

        WxPayOrderQueryResult wxPayOrderQueryResult = wxPayService.queryOrder(null, transactionId);

        if (wxPayOrderQueryResult.getTradeState().equals("SUCCESS")) {
            updateOrderTransactionStatus(orderId, PayStatusEnum.PAID, productType);
            LOGGER.info("user openid :{} ,pay succeed update OrderTransaction id {} ,wxOrderId: {}", wxPayOrderQueryResult.getOpenid(), orderId, wxPayOrderQueryResult.getTransactionId());
            LOGGER.info("user openid :{} ,pay succeed update OrderGood by OrderTransaction id {} ,wxOrderId: {}", wxPayOrderQueryResult.getOpenid(), orderId, wxPayOrderQueryResult.getTransactionId());
        } else if (wxPayOrderQueryResult.getTradeState().equals("CLOSED") || wxPayOrderQueryResult.getTradeState().equals("PAYERROR")) {
            updateOrderTransactionStatus(orderId, PayStatusEnum.PAY_FAILED, productType);
            LOGGER.info("user openid :{} ,pay failed update OrderTransaction id {} ,wxOrderId: {}", wxPayOrderQueryResult.getOpenid(), orderId, wxPayOrderQueryResult.getTransactionId());
        }
        return wxPayOrderQueryResult;
    }

    @Override
    public List<OrderGood> getShopOrder(Integer pageSize, Integer pageNum, String shopId, Double minAmount,
                                        Double maxAmount, Date startTime, Date endTime, String phone, String status) {

        String hql = "from OrderGood og where 1=1 ";
        if (shopId != null) {
            hql += " and og.shopId='" + shopId + "'";
        }
        if (minAmount != null) {
            hql += " and og.sumPrice>" + minAmount;
        }
        if (maxAmount != null) {
            hql += " and og.sumPrice<" + maxAmount;
        }
        if (startTime != null) {
            hql += " and og.createTime>'" + DateUtils.DateToString(startTime, "yyyy-MM-dd HH:mm:ss") + "'";
        }
        if (endTime != null) {
            hql += " and og.createTime<'" + DateUtils.DateToString(endTime, "yyyy-MM-dd HH:mm:ss") + "'";
        }
        if (StringUtils.isEmpty(status) == false && OrderEnum.ORDER_REFUND.toString().equals(status) == false && OrderEnum.ORDER_REFUNDED.toString().equals(status) == false) {
            hql += " and og.status='" + status + "'";
        }
        if (OrderEnum.ORDER_REFUND.toString().equals(status) == true || OrderEnum.ORDER_REFUNDED.toString().equals(status) == true) {
            String refundCondition = OrderEnum.ORDER_REFUND.toString().equals(status) ? " and og.refundStatus=1" : " and (og.refundStatus=2 or og.refundStatus=3) ";
            hql += refundCondition;
        }

        if (StringUtils.isEmpty(phone) == false) {
            hql += " and og.receivePhone like '%" + phone + "%'";
        }

        hql += " order by og.createTime desc";
        LOGGER.info("查询条件：{}", hql);
        List<OrderGood> orders = (List<OrderGood>) hibernateBaseDao.pageQuery(hql, pageNum, pageSize);
        return orders;
    }

    @Override
    public long countShopOrder(String shopId, Double minAmount, Double maxAmount, Date startTime, Date endTime, String phone, String status) {
        String hql = "select count(*) from OrderGood og where 1=1 ";
        if (shopId != null) {
            hql += " and og.shopId='" + shopId + "'";
        }
        if (minAmount != null) {
            hql += " and og.sumPrice>" + minAmount;
        }
        if (maxAmount != null) {
            hql += " and og.sumPrice<" + maxAmount;
        }
        if (startTime != null) {
            hql += " and og.createTime>'" + DateUtils.DateToString(startTime, "yyyy-MM-dd HH:mm:ss") + "'";
        }
        if (endTime != null) {
            hql += " and og.createTime<'" + DateUtils.DateToString(endTime, "yyyy-MM-dd HH:mm:ss") + "'";
        }
        if (StringUtils.isEmpty(status) == false && OrderEnum.ORDER_REFUND.toString().equals(status) == false && OrderEnum.ORDER_REFUNDED.toString().equals(status) == false) {
            hql += " and og.status='" + status + "'";
        }
        if (OrderEnum.ORDER_REFUND.toString().equals(status) == true || OrderEnum.ORDER_REFUNDED.toString().equals(status) == true) {
            String refundCondition = OrderEnum.ORDER_REFUND.toString().equals(status) ? " and og.refundStatus=1" : " and (og.refundStatus=2 or og.refundStatus=3) ";
            hql += refundCondition;
        }

        if (StringUtils.isEmpty(phone) == false) {
            hql += " and og.receivePhone like '%" + phone + "%'";
        }

        long count = hibernateBaseDao.count(hql);
        return count;
    }

    @Override
    public OrderGood getOrderById(String orderId) {
        if (StringUtils.isEmpty(orderId)) {
            throw new BizException("参数缺失!");
        }
        String hql = "from OrderGood og where id=?";
        return (OrderGood) hibernateBaseDao.getUnique(hql, orderId);
    }

    @Override
    public void updateOrderPrice(Double price, String remarks, String orderId) throws Exception {
        if (price == null) {
            throw new BizException("订单价格不能为空");
        }
        if (StringUtils.isEmpty(remarks)) {
            throw new BizException("修改价格请填写备注信息!");
        }
        if (StringUtils.isEmpty(orderId)) {
            throw new BizException("未找到对应的订单信息，修改失败!");
        }
        OrderGood og = getOrderById(orderId);
        if (og == null) {
            throw new BizException("未找到对应的订单信息，修改价格失败!");
        }
        og.setSumPrice(price);
        og.setCheckTime(new Timestamp(System.currentTimeMillis()));
        og.setStatus(OrderEnum.UNPAID);

        og.setRemarks((StringUtils.isEmpty(og.getRemarks()) ? "" : og.getRemarks() + ";") + remarks);
        LOGGER.info("用户:{}修改订单：" + orderId + "价格:" + price + "，备注：" + remarks, CurrentRequest.getCurrentUserId());
        hibernateBaseDao.update(og);
    }

    @Override
    public void cancelOrder(String orderId) {
        OrderGood orderGood = getOrderById(orderId);

        if (orderGood == null) {
            throw new BizException("未找到相关订单信息！");
        }
        if (OrderEnum.UNPAID.equals(orderGood.getStatus()) == false && OrderEnum.WAIT_EDIT_PRICE.equals(orderGood.getStatus()) == false) {
            throw new BizException("【" + orderGood.getStatus().getDesc() + "】状态的订单不允许取消!");
        }
        orderGood.setStatus(OrderEnum.ORDER_CANCEL);
        updateOrder(orderGood);

    }

    @Override
    public void postOrder(String orderId, String expressNo) {
        OrderGood orderGood = getOrderById(orderId);

        if (orderGood == null) {
            throw new BizException("未找到相关订单信息！");
        }

        if (StringUtils.isEmpty(expressNo)) {
            throw new BizException("发货请无比填入物流单号，以方便货物跟踪！");
        }


        orderGood.setStatus(OrderEnum.DELIVERED);
        orderGood.setExpressNo(expressNo);
        orderGood.setDeliverTime(new Timestamp(System.currentTimeMillis()));
        updateOrder(orderGood);

        if (StringUtils.isEmpty(orderGood.getReceivePhone()) == false) {
            try {
                smsService.businessSmsSend(orderGood.getReceivePhone(), ActionTypeEnum.TRADE_ORDER.toString());
            } catch (Exception ex) {
                LOGGER.error("短信发生失败!", ex);
            }
        }
    }

    @Override
    public void refundsOrder(String orderId, String reason, Double amount) {
        if (StringUtils.isEmpty(orderId)) {
            throw new BizException("订单信息不存在！");
        }
        OrderGood order = getOrderById(orderId);
        if (order == null) {
            throw new BizException("订单信息不存在！");
        }
        if (amount == null) {
            throw new BizException("金额不能为空!");
        }
        order.setRefundAmount(new BigDecimal(amount));
        order.setRefundReason(reason);
        order.setRefundStatus(1);
        hibernateBaseDao.update(order);
    }

    @Override
    public void refundsOrderDeal(String orderId, String reason, Integer status) {
        if (StringUtils.isEmpty(orderId)) {
            throw new BizException("订单信息不存在！");
        }
        OrderGood order = getOrderById(orderId);
        if (order == null) {
            throw new BizException("订单信息不存在！");
        }
        if (status == null) {
            throw new BizException("请选择同意或者不同意!");
        }
        if (status == 3) {
            order.setRefundReason(order.getRefundReason() + "回复：" + (StringUtils.isEmpty(reason) ? "无" : reason));
        }
        order.setRefundStatus(status);
        hibernateBaseDao.update(order);

    }

    @Override
    public void updateOrder(OrderGood orderGood) {
        hibernateBaseDao.update(orderGood);
    }

    @Override
    public List<OrderGood> getUserOrder(OrderEnum status, String userId, Integer pageNum, Integer pageSize) {
        String hql = "from OrderGood og where og.userId='" + userId + "'";
        if (status != null) {
            hql += " and og.status='" + status.toString() + "'";
        }

        hql += " order by og.createTime desc";

        return (List<OrderGood>) hibernateBaseDao.pageQuery(hql, pageNum, pageSize);
    }

    @Override
    public long countUserOrder(OrderEnum status, String userId) {
        String hql = "select count(id) from OrderGood og where og.userId=" + userId;
        if (status != null) {
            hql += " and og.status='" + status.toString() + "'";
        }
        return hibernateBaseDao.count(hql);
    }

    @Override
    public List<OrderGood> getShopOrder(OrderEnum status, String userId, Integer refundsStatus, Integer pageNum, Integer pageSize) {
        String hql = "from OrderGood og where og.shopId=?";
        if (status != null) {
            hql += " and og.status='" + status.toString() + "'";
        }

        if (refundsStatus != null) {
            hql += " and og.refundStatus=" + refundsStatus;
        }

        hql += " order by og.createTime desc";
        return (List<OrderGood>) hibernateBaseDao.pageQuery(hql, pageNum, pageSize, userId);
    }

    @Override
    public long countShopOrder(OrderEnum status, String userId) {
        String hql = "select count(id) from OrderGood og where og.shopId = ?";
        if (status != null) {
            hql += " and og.status='" + status.toString() + "'";
        }
        return hibernateBaseDao.count(hql, userId);
    }

    @Override
    public OrderTransaction getOrderTransactionById(String orderId) {
        if (StringUtils.isEmpty(orderId)) {
            throw new BizException("参数缺失!");
        }
        String hql = "from OrderTransaction ot where id=?";
        return (OrderTransaction) hibernateBaseDao.getUnique(hql, orderId);
    }

    @Override
    public void updateOrderTransactionWxOrder(String orderId, String wxOrderId, String totalFee, ProductTypeEnum productType) throws Exception {
        if (StringUtils.isEmpty(orderId)) {
            throw new BizException("参数缺失!");
        }
        String hql = "from OrderTransaction ot where id = ?";
        OrderTransaction orderTransaction = (OrderTransaction) hibernateBaseDao.getUnique(hql, orderId);
        if (CommonUtils.isEmpty(orderTransaction)) {
            throw new BizException("交易订单信息不存在");
        }
        if (!orderTransaction.getAmount().equals(Double.parseDouble(totalFee))) {
            updateOrderTransactionStatus(orderId, PayStatusEnum.WRONG_FEE, productType);
            throw new BizException("支付金额与订单信息不符");
        }

        orderTransaction.setUpdateTime(new Timestamp(System.currentTimeMillis()));
        orderTransaction.setWxOrderId(wxOrderId);
        hibernateBaseDao.save(orderTransaction);
    }

    @Override
    public void updateOrderTransactionStatus(String orderId, PayStatusEnum payStatusEnum, ProductTypeEnum productType) throws Exception {
        String hql = "from OrderTransaction ot where id=?";
        OrderTransaction orderTransaction = (OrderTransaction) hibernateBaseDao.getUnique(hql, orderId);
        if (CommonUtils.isEmpty(orderTransaction)) {
            throw new BizException("交易订单信息不存在");
        }
        switch (payStatusEnum) {
            case PAYING:
                if (orderTransaction.getPayStatus().equals(PayStatusEnum.UNPAID)) {
                    orderTransaction.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                    orderTransaction.setPayStatus(payStatusEnum);
                }
                break;
            case PAY_FAILED:
                if (orderTransaction.getPayStatus().equals(PayStatusEnum.PAYING)) {
                    orderTransaction.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                    orderTransaction.setPayStatus(payStatusEnum);
                }
                break;
            case PAY_TIMEOUT:
                if (orderTransaction.getPayStatus().equals(PayStatusEnum.PAYING)) {
                    orderTransaction.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                    orderTransaction.setPayStatus(payStatusEnum);
                }
                break;
            case PAID:
                if (orderTransaction.getPayStatus().equals(PayStatusEnum.PAYING)) {
                    orderTransaction.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                    orderTransaction.setPayStatus(payStatusEnum);

                    updateOrderStatus(orderId, productType, OrderEnum.PAYMENT_SUCCESS);
                }

                break;
            case WRONG_FEE:
                if (orderTransaction.getPayStatus().equals(PayStatusEnum.PAYING)) {
                    orderTransaction.setUpdateTime(new Timestamp(System.currentTimeMillis()));
                    orderTransaction.setPayStatus(payStatusEnum);
                }
                break;
        }
        hibernateBaseDao.update(orderTransaction);
    }

    private void updateOrderStatus(String transactionOrderId, ProductTypeEnum productType, OrderEnum orderEnum) throws Exception {
        switch (productType) {
            case CUSTOM_SERVICE:

                break;

            case FORUM_AD:
                List<OrderArticleAd> orders = articleAdService.getByOrderTransactionOrderId(transactionOrderId);
                if (CollectionUtils.isEmpty(orders)) {
                    throw new BizException("订单信息不存在");
                }
                for (OrderArticleAd order : orders) {
                    if (OrderEnum.PAYING.equals(order.getStatus())) {
                        order.setStatus(orderEnum);
                        String articleId = order.getArticleId();
                        DBObject article = articleService.getArticleInfo(articleId);
                        DBObject flags = article.containsField("ad_option") ? (DBObject) article.get("ad_option") : new BasicDBObject();

                        if (article.containsField("ad_option") && flags.containsField(order.getAdType().toString())) {
                            DBObject flag = (DBObject) flags.get(order.getAdType().toString());
                            Date endTime = (Date) flag.get("end_time");
                            endTime = new Date(endTime.getTime() + DateUtils.getTimeBetween(order.getStartTime().getTime(), order.getEndTime().getTime()));
                            flag.put("end_time", endTime);
                        } else {
                            DBObject flag = new BasicDBObject();
                            flag.put("start_time", new Date());
                            flag.put("end_time", new Date(order.getEndTime().getTime()));
                            flags.put(order.getAdType().toString(), flag);
                        }
                        articleService.updateArticle(articleId, new BasicDBObject("ad_option", flags));
                    }
                }

                break;
            case GOOD:
                updateOrderGoodStatus(transactionOrderId, orderEnum);
                break;
        }
    }


    @Override
    public void updateOrderGoodStatus(String orderId, OrderEnum orderEnum) throws Exception {
        String hql = "from OrderGood where transactionOrderId = ?";
        List<OrderGood> orderGoods = (List<OrderGood>) hibernateBaseDao.queryForList(hql, orderId);
        if (CommonUtils.isEmpty(orderGoods)) {
            return;
        }
        Timestamp now = new Timestamp(System.currentTimeMillis());
        for (OrderGood orderGood : orderGoods) {
            switch (orderEnum) {
                case PAYMENT_SUCCESS:
                    if (orderGood.getStatus().equals(OrderEnum.UNPAID)) {
                        orderGood.setStatus(orderEnum);
                        orderGood.setPayTime(now);
                        goodMgrService.addGoodSales(orderGood.getGoodId());
                    }
                    hibernateBaseDao.save(orderGood);
                    break;

            }
        }

    }

    @Override
    public List<OrderTransaction> getOrderTransactionPayingList() {
        String hql = "from OrderTransaction where payStatus = ? and updateTime < ?";
        Timestamp thrityMinAgo = new Timestamp(System.currentTimeMillis() - (30 * 60 * 1000));
        return (List<OrderTransaction>) hibernateBaseDao.queryForList(hql, PayStatusEnum.PAYING, thrityMinAgo);
    }

    @Override
    public void updateUserOrderComplete(SystemUser user, String orderId) throws BizException {
        String hql = "from OrderGood where id = ? and userId = ?";
        OrderGood orderGood = (OrderGood) hibernateBaseDao.getUnique(hql, orderId, user.getId());
        if (CommonUtils.isEmpty(orderGood)) {
            throw new BizException("订单信息不存在");
        }
        Timestamp now = new Timestamp(System.currentTimeMillis());
        if (orderGood.getStatus().equals(OrderEnum.DELIVERED)) {
            orderGood.setStatus(OrderEnum.RECED_CONFIRMATION);
            orderGood.setCompleteTime(now);
            orderGood.setCompleteType(1);
            hibernateBaseDao.update(orderGood);
        } else {
            throw new BizException("订单状态不正确，无法确认收货");
        }

    }

    @Override
    public List<OrderGood> getAutoCompleteOrderGoodList() {
        String hql = "from OrderGood where status = ? and deliverTime < ?";
        Date now = new Date();
        Date expireDate = DateUtils.addDay(now, -15);
        return (List<OrderGood>) hibernateBaseDao.queryForList(hql, OrderEnum.DELIVERED, new Timestamp(expireDate.getTime()));
    }

    @Override
    public void updateAutoCompleteOrderGood(OrderGood orderGood) {
        Date now = new Date();
        Timestamp nowTime = new Timestamp(now.getTime());
        orderGood.setStatus(OrderEnum.RECED_CONFIRMATION);
        orderGood.setCompleteTime(nowTime);
        orderGood.setCompleteType(2);
        hibernateBaseDao.update(orderGood);
    }

    @Override
    public void updateTransferCompleteOrder(OrderGood orderGood) {
        Date now = new Date();
        Timestamp nowTime = new Timestamp(now.getTime());
        Double fee = orderGood.getSumPrice();
        String userId = orderGood.getUserId();
        String shopId = orderGood.getShopId();
        String orderId = orderGood.getId();
        String hql = "from AccountBalance where wx_user_id = ?";
        AccountBalance accountBalance = (AccountBalance) hibernateBaseDao.getUnique(hql, shopId);
        accountBalance.setBalance(accountBalance.getBalance().add(new BigDecimal(fee)));
        accountBalance.setLastTime(nowTime);
        hibernateBaseDao.update(accountBalance);
        OrderTransfer orderTransfer = new OrderTransfer();
        orderTransfer.setId(UUID.randomUUID().toString().replaceAll("-", ""));
        orderTransfer.setFee(new BigDecimal(fee));
        orderTransfer.setFromUserId(userId);
        orderTransfer.setToShopId(shopId);
        orderTransfer.setOrderId(orderId);
        hibernateBaseDao.save(orderTransfer);
        orderGood.setIsTransfer(1);
        hibernateBaseDao.update(orderGood);
        LOGGER.info("订单金额结算到商户。订单号：{}，用户id：{}，商户id：{}，金额：{}", orderId, userId, shopId, fee);

    }

    @Override
    public List<OrderGood> getTransferCompleteOrderList() {
        String hql = "from OrderGood where status = ? and completeTime < ? and isTransfer = 0";
        Date now = new Date();
        Date expireDate = DateUtils.addDay(now, -7);
        List<OrderGood> orderGoods = (List<OrderGood>) hibernateBaseDao.queryForList(hql, OrderEnum.RECED_CONFIRMATION, new Timestamp(expireDate.getTime()));
        return orderGoods;
    }


    @Override
    public List<Map<String, Object>> getFullInfoOrder(List<OrderGood> orders) {
        return null;
    }


    private WxPayService setWxPayConfig(ClientTypeEnum clientType, ProductTypeEnum productType) {
        WxPayServiceImpl wxPayService = new WxPayServiceImpl();

        WxPayConfig wxPayConfig = new WxPayConfig();
        switch (clientType) {
            case wechat:
                wxPayConfig.setAppId(mainConfig.getAppid());
                wxPayConfig.setMchId(mainConfig.getPartenerId());
                wxPayConfig.setMchKey(mainConfig.getPartenerKey());
                wxPayConfig.setTradeType("JSAPI");
                break;
            case web:
                wxPayConfig.setTradeType("NATIVE");
                wxPayConfig.setAppId(mainConfig.getAppid());
                wxPayConfig.setMchId(mainConfig.getPartenerId());
                wxPayConfig.setMchKey(mainConfig.getPartenerKey());
                break;
            case app:
            default:
                wxPayConfig.setTradeType("APP");
                wxPayConfig.setAppId(mainConfig.getMobileAppid());
                wxPayConfig.setMchId(mainConfig.getMobilePartenerId());
                wxPayConfig.setMchKey(mainConfig.getMobilePartenerKey());


        }
        wxPayConfig.setNotifyUrl(mainConfig.getDomain() + "/notify/result/" + clientType.toString() + "/" + productType);
        wxPayService.setConfig(wxPayConfig);
        return wxPayService;
    }
}
